const PARSE_STATE = {
  INIT: 'INIT',
  KEY: 'KEY',
  SEPARATOR: 'SEPARATOR',
  VALUE: 'VALUE',
  CLOSE: 'CLOSE',
}

const VALUE_TYPE = {
  PRIMITIVE: 'PRIMITIVE',
  OBJECT: 'OBJECT',
  ARRAY: 'ARRAY',
  COMMENT: 'COMMENT',
}
export function obj2ast(input = '', options = {}) {
  const DEFAULT_OPTIONS = {
    maxDepth: 50, // 最大嵌套深度
  }
  // 合并默认选项和用户提供的选项
  options = Object.assign({}, DEFAULT_OPTIONS, options)

  let index = 0 // 当前解析的字符索引
  let currentContext = null // 当前解析上下文
  const stack = [] // 上下文堆栈，用于处理嵌套结构
  let depth = 0 // 当前嵌套深度
  let ast = null
  let jsonContext = null
  const jsonStack = [] // 上下文堆栈，用于处理嵌套结构

  let json = null
  let lastKey = null
  let tempComment = null
  const commentMap = {}

  // 创建对象节点
  const createObjectNode = () => ({ type: 'Object', before: [], after: [], children: [], state: PARSE_STATE.INIT })
  // 创建数组节点
  const createArrayNode = () => ({ type: 'Array', before: [], after: [], children: [], state: PARSE_STATE.INIT })
  // 创建属性节点
  const createPropertyNode = () => ({ type: 'Property', before: [], after: [], state: PARSE_STATE.INIT, key: null, value: null })
  // 创建值节点
  const createPrimitiveNode = value => ({ type: 'Primitive', before: [], after: [], state: PARSE_STATE.INIT, value })

  // 创建注释节点
  const createCommentNode = (value = '') => ({ type: 'Comment', state: PARSE_STATE.INIT, value })
  // 移动索引
  const advance = (n = 1) => index += n
  // 获取当前字符
  const currentChar = () => input[index]
  // 获取前n个字符
  const lookAhead = (n = 1) => input.slice(index, index + n)
  // 判断字符是否为空白字符
  const isWhitespace = c => /\s/.test(c)
  // 处理注释
  const parseCommentsAndWhitespace = () => {
    const comments = []
    while (index < input.length) {
      if (lookAhead(2) === '//') {
        advance(2)
        let comment = '//'
        while (currentChar() !== '\n' && index < input.length) {
          comment += currentChar()
          advance()
        }
        comments.push(createCommentNode(comment))

        continue
      }
      if (lookAhead(2) === '/*') {
        advance(2)
        let comment = '/*'
        while (lookAhead(2) !== '*/' && index < input.length) {
          comment += currentChar()
          advance()
        }
        comment += '*/'
        advance(2)
        comments.push(createCommentNode(comment))

        continue
      }
      if (isWhitespace(currentChar())) {
        advance()
      }
      else {
        break
      }
    }
    return comments
  }
  const retryParse = () => {
    advance()
    currentContext = null
    stack.length = 0
    ast = null
    json = null
    jsonStack.length = 0
    jsonContext = null
    lastKey = null
  }
  // 解析字符串（支持转义）
  const parseString = (quote) => {
    let value = ''
    advance() // 跳过起始引号
    while (index < input.length) {
      const c = currentChar()
      if (c === '\\') {
        advance()
        const escapeChar = currentChar()
        value += {
          'b': '\b',
          'f': '\f',
          'n': '\n',
          'r': '\r',
          't': '\t',
          '"': '"',
          '\'': '\'',
          '\\': '\\',
        }[escapeChar] || escapeChar
        advance()
      }
      else if (c === quote) {
        advance()
        return value
      }
      else {
        value += c
        advance()
      }
    }
    throw new SyntaxError('Unterminated string')
  }

  // 解析键
  const parseKey = () => {
    const c = currentChar()

    if (c === '"' || c === '\'') {
      const keyNode = { type: VALUE_TYPE.PRIMITIVE, value: parseString(c) }
      return keyNode
    }

    // 标识符键（JS模式）
    if (/[a-z_$]/i.test(c)) {
      let key = ''
      while (index < input.length && /[\w$]/.test(currentChar())) {
        key += currentChar()
        advance()
      }
      return { type: VALUE_TYPE.PRIMITIVE, value: key }
    }
    throw new SyntaxError(`Unexpected key character: ${c}`)
  }
  const numPattern = /[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[-+]?\d+)?/i
  // 解析值
  const parseValue = () => {
    const c = currentChar()

    if (c === '{') {
      advance()
      return { type: VALUE_TYPE.OBJECT }
    }

    if (c === '[') {
      advance()
      return { type: VALUE_TYPE.ARRAY }
    }

    if (c === '"' || c === '\'') {
      return { type: VALUE_TYPE.PRIMITIVE, value: parseString(c) }
    }

    if (c === 't' && lookAhead(4) === 'true') {
      advance(4)
      return { type: VALUE_TYPE.PRIMITIVE, value: true }
    }

    if (c === 'f' && lookAhead(5) === 'false') {
      advance(5)
      return { type: VALUE_TYPE.PRIMITIVE, value: false }
    }

    if (c === 'n' && lookAhead(4) === 'null') {
      advance(4)
      return { type: VALUE_TYPE.PRIMITIVE, value: null }
    }

    if (c === 'u' && lookAhead(9) === 'undefined') {
      advance(9)
      return { type: VALUE_TYPE.PRIMITIVE, value: undefined }
    }

    const rawStr = input.slice(index)
    const match = rawStr.match(numPattern)
    if (match) {
      const numStr = match[0]
      advance(numStr.length)
      return { type: VALUE_TYPE.PRIMITIVE, value: Number(numStr) }
    }

    throw new SyntaxError(`Unexpected token: ${c}`)
  }

  // 主解析循环
  try {
    while (index < input.length) {
      if (!currentContext) {
        const before = parseCommentsAndWhitespace()
        const c = currentChar()
        const isObjOrArr = c === '{' || c === '['
        if (isObjOrArr) {
          const isObj = c === '{'
          currentContext = c === '{' ? createObjectNode() : createArrayNode()
          jsonContext = isObj ? {} : []
          if (!ast) {
            ast = currentContext
            json = jsonContext
          }
          jsonStack.push(jsonContext)
          stack.push(currentContext)
          depth++
          if (before.length > 0) {
            commentMap.rootBefore = before
            currentContext.before.push(...before)
          }
          advance()
          continue
        }
        // 未解析到对象或数组往后跳，一直往后尝试解析，直到找到对象或数组

        retryParse()
        continue
      }
      switch (currentContext.state) {
        case PARSE_STATE.INIT: {
          if (currentContext.type === 'Object') {
            currentContext.state = PARSE_STATE.KEY
          }
          else {
            currentContext.state = PARSE_STATE.VALUE
          }
          break
        }

        case PARSE_STATE.KEY: {
          const before = parseCommentsAndWhitespace()
          let keyResult
          try {
            keyResult = parseKey()
          }
          catch (error) {
            retryParse()
            continue
          }

          const after = parseCommentsAndWhitespace()

          const newContext = createPropertyNode()
          lastKey = keyResult.value
          newContext.key = lastKey
          jsonContext[lastKey] = null
          if (tempComment) {
            newContext.before.push(...tempComment)
            tempComment = null
          }

          if (before.length > 0) {
            newContext.before.push(...before)
          }
          if (after.length > 0) {
            newContext.after.push(...after)
          }

          currentContext.children.push(newContext)
          currentContext.state = PARSE_STATE.SEPARATOR
          break
        }

        case PARSE_STATE.SEPARATOR: {
          const c = currentChar()
          if (c !== ':') {
            retryParse()
            continue
            // throw new SyntaxError('Expected \':\' after key')
          }
          advance()
          currentContext.state = PARSE_STATE.VALUE
          break
        }

        case PARSE_STATE.VALUE: {
          const before = parseCommentsAndWhitespace() // 获取值前的注释
          const c = currentChar()
          if (c === ']') {
            currentContext.state = PARSE_STATE.CLOSE
            break
          }
          const valueResult = parseValue()

          if (valueResult.type !== VALUE_TYPE.PRIMITIVE) {
            const isObjNode = valueResult.type === VALUE_TYPE.OBJECT
            const newContext = isObjNode ? createObjectNode() : createArrayNode()
            const newJsonContext = isObjNode ? {} : []

            if (tempComment) {
              newContext.before.push(...tempComment)
              tempComment = null
            }
            if (before.length > 0) {
              newContext.before.push(...before)
            }

            if (currentContext.type === 'Object') {
              jsonContext[lastKey] = newJsonContext
              const Context = currentContext.children[currentContext.children.length - 1]
              Context.value = newContext
            }
            else {
              jsonContext.push(newJsonContext)

              currentContext.children.push(newContext)
            }

            stack.push(newContext)
            jsonStack.push(newJsonContext)

            currentContext = newContext
            jsonContext = newJsonContext

            depth++
            if (depth > options.maxDepth)
              throw new SyntaxError(`Exceeded max depth ${options.maxDepth}`)
            const keybefore = parseCommentsAndWhitespace() // 获取值前的注释

            const nextChar = currentChar()
            if (nextChar === '}' || nextChar === ']') { // empty object or array
              currentContext.state = PARSE_STATE.CLOSE
              if (keybefore.length > 0) { // 空数组或者空对象会走这儿
                newContext.before.push(...keybefore)
              }
              continue
            }
            else {
              tempComment = keybefore
            }
            if (newContext.type === 'Object') {
              currentContext.state = PARSE_STATE.KEY
            }
            else {
              currentContext.state = PARSE_STATE.VALUE
            }
          }
          else {
            if (tempComment) {
              currentContext.before.push(...tempComment)
              tempComment = null
            }
            const after = parseCommentsAndWhitespace() // 获取值后的注释

            if (currentContext.type === 'Object') {
              const prop = currentContext.children[currentContext.children.length - 1]
              prop.value = createPrimitiveNode(valueResult.value)
              jsonContext[lastKey] = valueResult.value

              if (before.length > 0) {
                prop.value.before.push(...before)
              }
              if (after.length > 0) {
                prop.value.after.push(...after)
              }

              const nextChar = currentChar()
              if (nextChar === ',') {
                advance()
                const after = parseCommentsAndWhitespace()

                if (currentChar() === '}') { // 尾逗号情况
                  if (after.length > 0) {
                    currentContext.after.push(...after)
                  }
                  currentContext.state = PARSE_STATE.CLOSE
                }
                else { // 还有key，解析下一个key值
                  tempComment = after
                  currentContext.state = PARSE_STATE.KEY
                }
              }
              else {
                currentContext.state = PARSE_STATE.CLOSE
              }
            }
            else {
              const valueNode = createPrimitiveNode(valueResult.value)
              if (before.length > 0) {
                valueNode.before.push(...before)
              }
              if (after.length > 0) {
                valueNode.after.push(...after)
              }

              //   json[lastKey].push(valueResult.value)
              jsonContext.push(valueResult.value)
              currentContext.children.push(valueNode)
              const nextChar = currentChar()
              if (nextChar === ',') {
                advance()
                const after = parseCommentsAndWhitespace()

                if (currentChar() === ']') {
                  if (after.length > 0) {
                    currentContext.after.push(...after)
                  }
                  currentContext.state = PARSE_STATE.CLOSE
                }
                else {
                  tempComment = after
                  currentContext.state = PARSE_STATE.VALUE
                }
              }
              else {
                currentContext.state = PARSE_STATE.CLOSE
              }
            }
          }
          break
        }

        case PARSE_STATE.CLOSE: {
          // const before = parseCommentsAndWhitespace()
          const expectedEnd = currentContext.type === 'Object' ? '}' : ']'
          const c = currentChar()

          if (c === expectedEnd) {
            advance()
            const after = parseCommentsAndWhitespace()
            const context = stack.pop()
            jsonStack.pop()

            if (after.length > 0) {
              context.after.push(...after)
            }
            depth--

            currentContext = stack.length ? stack[stack.length - 1] : null
            jsonContext = jsonStack.length ? jsonStack[stack.length - 1] : null

            if (currentContext) {
              const nextChar = currentChar()
              if (nextChar === ',') {
                advance()
                const after = parseCommentsAndWhitespace()
                const isEnd = currentChar()
                if (isEnd === ']' || isEnd === '}') {
                  if (after.length > 0) {
                    context.after.push(...after)
                  }
                  currentContext.state = PARSE_STATE.CLOSE
                }
                else {
                  tempComment = after
                  currentContext.state = currentContext.type === 'Object' ? PARSE_STATE.KEY : PARSE_STATE.VALUE
                }
              }
              else {
                currentContext.state = PARSE_STATE.CLOSE
              }
            }
            else {
              return { ast, json }
            }
          }
          else {
            retryParse()
            continue
            // throw new SyntaxError(`Unexpected token: ${currentChar()}, expected ${expectedEnd}`)
          }
          break
        }
      }
    }

    return { ast, json }
  }
  catch (e) {
    // 生成错误位置信息
    const line = input.slice(0, index).split('\n').length
    const column = index - input.slice(0, index).lastIndexOf('\n') - 1
    e.message += ` at line ${line} column ${column}`
    throw e
  }
}

export function transformer(ast, visit) {
  if (!ast || !ast.type || !ast.children) {
    throw new Error('Invalid AST structure')
  }
  const addComment = (node, key = 'before') => {
    let comment = ''
    if (node[key].length > 0) {
      comment = `${node[key].map(e => e.value).join('\n')}\n`
    }
    return comment
  }
  let json = null
  let rawStr = ''

  if (ast.type === 'Object') {
    json = {}
    const parts = []
    for (const child of ast.children) {
      if (!child.key || !child.value) {
        throw new Error('Invalid child structure')
      }
      const isFilter = visit && visit(child)

      if (child.value.type === 'Primitive') {
        const val = child.value.value
        if (!isFilter) {
          parts.push(`  ${addComment(child)}  "${child.key}":${typeof val === 'string' ? `"${val}"` : val}`)
        }
        json[child.key] = val
      }
      else {
        const result = transformer(child.value)
        if (!isFilter) {
          parts.push(`  ${addComment(child)}"${child.key}":${result.rawStr}`)
        }
        json[child.key] = result.json
      }
    }
    rawStr = `{\n${parts.join(',\n')}\n}`
  }
  else if (ast.type === 'Array') {
    const results = ast.children.map(child => {
      const res = transformer(child)

      res.rawStr = `${addComment(child)}${res.rawStr}\n${addComment(child, 'after')}`
      return res
    })

    json = results.map(result => result.json)
    rawStr = `[\n${results.map(result => result.rawStr).join(',\n')}]`
  }
  else {
    throw new Error('Unsupported AST type')
  }

  return { json, rawStr }
}

export function parseComment(ast) {
  const comment = {}
  function traverse(ast, path = '') {
    if (!ast) return {}
    if (ast.type === 'Object') {
      for (const child of ast.children) {
        const fullPath = path ? `${path}.${child.key}` : child.key
        if (child.value && child.value.type === 'Primitive') {
          if (child.before.length > 0) {
            comment[`${fullPath}_before`] = child.before
          }
          if (child.after.length > 0) {
            comment[`${fullPath}_after`] = child.after
          }
        }
        else {
          if (child.before.length > 0) {
            comment[`${fullPath}_before`] = child.before
          }
          if (child.after.length > 0) {
            comment[`${fullPath}_after`] = child.after
          }
          traverse(child.value, fullPath)
        }
      }
    }
    else if (ast.type === 'Array') {
      ast.children.forEach((child, index) => {
        const fullPath = path ? `${path}[${index}]` : `[${index}]`
        if (child.before.length > 0) {
          comment[`${fullPath}_before`] = child.before
        }
        if (child.after.length > 0) {
          comment[`${fullPath}_after`] = child.after
        }
        traverse(child, fullPath)
      })
    }
    else {
      throw new Error('Unsupported AST type')
    }
  }
  traverse(ast)
  return comment
}

/**
 * 递归格式化 AST
 * @param {object} node - AST 节点
 * @param {number} indentLevel - 当前缩进层级
 * @returns {string} - 格式化后的字符串
 */
export function astToJSON5(node, indentLevel = 0) {
  const indent = '  '.repeat(indentLevel) // 根据缩进层级生成空格
  const childIndent = '  '.repeat(indentLevel + 1) // 子节点缩进

  if (node.type === 'Object') {
    // 处理对象
    const properties = node.children
      .map(child => {
        if (child.type === 'Property') {
          // 处理属性，将 key 转换为双引号
          const key = `"${child.key}"` // 使用双引号包裹 key
          const value = astToJSON5(child.value, indentLevel + 1)
          const before = child.before
            ? child.before.map(c => `${childIndent}${c.value}`).join('\n') // 注释缩进
            : ''
          const after = child.after
            ? child.after.map(c => `${childIndent}${c.value}`).join('\n') // 注释缩进
            : ''
          return `${before}\n${childIndent}${key}: ${value}${after}`
        }
        return ''
      })
      .filter(Boolean) // 过滤空值
      .join(',\n')
    return `{\n${properties}\n${indent}}`
  }
  else if (node.type === 'Primitive') {
    // 处理原始值
    return JSON.stringify(node.value)
  }
  else if (node.type === 'Array') {
    // 处理数组
    const items = node.children
      .map(child => {
        const before = child.before
          ? child.before.map(c => `${childIndent}${c.value}`).join('\n') // 注释缩进
          : ''
        const after = child.after
          ? child.after.map(c => `${childIndent}${c.value}`).join('\n') // 注释缩进
          : ''
        const value = astToJSON5(child, indentLevel + 1)
        return `${before}\n${childIndent}${value}${after}`
      })
      .join(',\n')
    return `[\n${items}\n${indent}]`
  }
  else {
    // 其他类型直接返回空对象
    return '{}'
  }
}
